require_relative '../util/byte_buffer'
require_relative 'command_id'
require_relative 'pdu_error'
require_relative 'alert_notification'
require_relative 'bind_receiver'
require_relative 'bind_receiver_resp'
require_relative 'bind_transceiver'
require_relative 'bind_transceiver_resp'
require_relative 'bind_transmitter'
require_relative 'bind_transmitter_resp'
require_relative 'enquire_link'
require_relative 'enquire_link_resp'
require_relative 'unbind'
require_relative 'unbind_resp'

module SmppClient

  module Pdu

      # Parse PDU and control command id to PDU mapping.

      module PduFactory

        include SmppClient::Util

        @command_ids = {
                CommandId::ALERT_NOTIFICATION => AlertNotification,
                CommandId::BIND_RECEIVER => BindReceiver,
                CommandId::BIND_RECEIVER_RESP => BindReceiverResp,
                CommandId::BIND_TRANSCEIVER => BindTransceiver,
                CommandId::BIND_TRANSCEIVER_RESP => BindTransceiverResp,
                CommandId::BIND_TRANSMITTER => BindTransmitter,
                CommandId::BIND_TRANSMITTER_RESP => BindTransmitterResp,
                CommandId::ENQUIRE_LINK => EnquireLink,
                CommandId::ENQUIRE_LINK_RESP => EnquireLinkResp,
                CommandId::UNBIND => Unbind,
                CommandId::UNBIND_RESP => UnbindResp
        }

        def self.parse(byte_buffer)
          command_id = ByteBuffer.new(byte_buffer.bytes[4, 4]).remove_int
          clazz = @command_ids[command_id]
          raise PduError, "PDU corresponding to command id #{command_id} is not found." if clazz == nil
          clazz.new(byte_buffer)
        end

        def self.add(const_name, const_value, clazz)
          if @command_ids.has_key?(const_value)
            raise PduError, "Command id #{const_value} already mapped to #{@command_ids[const_value]} class."
          end
          CommandId.const_set(const_name, const_value)
          @command_ids[const_value] = clazz
        end

        def self.remove(const)
          @command_ids.delete(const)
        end

      end

  end

end